home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / drdobbs / 1987 / 09 / kleinlst.sep < prev    next >
Text File  |  1987-08-13  |  16KB  |  618 lines

  1. Listing One
  2.  
  3. ;  prndrv.asm
  4. ;        printer driver startup code
  5. ;        ms/pc-dos 2.x, 3.x installable device driver 
  6. ;copyright (c) Andy Klein 1987
  7.  
  8.  
  9. PRIVATE_STACK_SIZ  equ  256   ;private stack size, probably much larger
  10.                               ;  than necessary
  11.  
  12.  
  13. IS_CHAR_DEV  equ 32768        ;bit to set for this driver
  14.  
  15.  
  16. codeseg    segment para public 'CODE'
  17. codeseg    ends
  18.  
  19. dataseg    segment para public 'DATA'    ; define first
  20. dataseg    ends
  21.  
  22.  
  23.     assume    cs:codeseg, ds:dataseg, es:dataseg, ss:dataseg
  24.  
  25.  
  26. codeseg    segment para public 'CODE'
  27.  
  28.     org    0        ;drivers are always org'ed at 0
  29.                     ;  with the device header first
  30.  
  31. public prn_driver, dev_strategy_, dev_interrupt_
  32.  
  33.  
  34. prn_driver    proc    far  ;drivers invoked as far calls by DOS
  35.  
  36.         ;device header starts here
  37.  
  38. next_dev   db 4 dup(255)        ;no next driver in this file, need a
  39.                                 ;(long)-1 which is 4 bytes of 255
  40. attribute  dw    IS_CHAR_DEV    
  41. strategy   dw    dev_strategy_  ;device strategy entry point
  42. interrupt  dw    dev_interrupt_ ;device interrupt entry point 
  43. dev_name   db    'PRN     '
  44.  
  45.         ;end of the device header
  46.  
  47.  
  48.     ;code segment variables, these will be addressable before we setup
  49.     ; our data and stack segment
  50. req_hdr_seg  dw    (0)   ; pointer to request header, segment part
  51. req_hdr_off  dw    (0)   ; pointer to request header, offset part
  52. caller_ss    dw    (0)   ; caller's ss
  53. caller_sp    dw    (0)   ; caller's sp 
  54.  
  55.     
  56.         ;strategy - this strategy function saves a long pointer to a
  57.         ;  request header in code segment variables req_hdr_seg and
  58.         ;  req_hdr_off.
  59.         ;  The address of the request header is passed in es:bx
  60.  
  61. dev_strategy_:
  62.  
  63.     mov word ptr cs:req_hdr_off,bx     ;save request header pointer
  64.     mov word ptr cs:req_hdr_seg,es     ;  in code segment variables
  65.     ret                                ; ...and back to dos
  66.  
  67.  
  68. public $cswt, $begin    ;keep Aztec linker happy, all Aztec C compiled
  69.                         ; functions have a reference to these 2 functions
  70.                         ; which normally drag in the startup code
  71.  
  72.     $cswt proc near
  73.     $cswt endp
  74.  
  75.     $begin proc near
  76.     $begin endp
  77.  
  78.  
  79.     extrn    driver_functions_:near
  80.  
  81.     ;interrupt - not a true interrupt handler (it ends with a ret as opposed
  82.     ; to an iret), this function recieves no parameters.  Instead it
  83.     ; uses the information stored in the request header we recieved and
  84.     ; saved a pointer to in the strategy function to determine what to do.
  85.  
  86.  
  87. dev_interrupt_: 
  88.             ;STEP 0
  89.             ; Preserve machine state
  90.     cli             ; no interrupts when dealing with machine state
  91.     push ds         ; save machine state on caller's stack
  92.     push es
  93.     push ax
  94.     push bx
  95.     push cx
  96.     push dx
  97.     push si
  98.     push di
  99.     push bp
  100.     pushf
  101.     mov cs:caller_ss,ss     ; save caller stack frame (ss and sp)
  102.     mov cs:caller_sp,sp   
  103.     sti                     ;interrupts OK
  104.  
  105.             ;Now the real work starts ...
  106.  
  107.             ;STEP 1
  108.             ; Get the driver's segment into the ax register
  109.             ; This begins our task of establishing addressability
  110.  
  111.     mov ax,cs    
  112.  
  113.             ;STEP 2   
  114.             ;  Copy the request header stored at req_hdr_seg:req_hdr_off
  115.             ;  into our private and C addressable request header
  116.  
  117.     mov si,cs:req_hdr_off        ;load up the source string segment:offset
  118.     mov bx,cs:req_hdr_seg        ; into ds:si registers
  119.     mov ds,bx    
  120.     mov es,ax                    ;load up the destination string segment:offset
  121.     mov di,offset cs:driver_rh_  ; into es:di registers
  122.     cld                          ;set direction flag to increment si and di
  123.     xor cx,cx                    ;clear out cx
  124.     mov cl,[si]                  ;first byte of request header is its length
  125.     rep movsb                    ; ... and copy it ...
  126.  
  127.  
  128.             ;STEP 3
  129.             ;  This step establishes addressability of data segment
  130.             ;  and sets up driver's stack frame.
  131.             ;  It also sets register bp equal to sp, a state required
  132.             ;  for calling the first C function
  133.             ;       Remember that register ax contains the driver segment
  134.             ;       We will set ds, es, ss all equal to cs ... 8080 model??
  135.  
  136.     mov bx,offset c_stack_top    ;this will go into sp
  137.     cli               ;no interrupts while we mess with these registers
  138.     mov ds,ax
  139.     mov es,ax
  140.     mov ss,ax         ;now establish our stack frame
  141.     mov sp,bx
  142.     mov bp,bx         ;bp = sp  this is critical for C
  143.     sti               ;ok for an interrupt to occur
  144.             ;now we have set up the environment for C
  145.     
  146.  
  147.             ;STEP 4
  148.             ; Call our first C function, 
  149.             ; passing the command code from the request header as
  150.             ; a parameter.  (void)driver_functions(cmd_code); 
  151.  
  152.     xor ax,ax                   ;clear out ax
  153.     mov bx,offset driver_rh_    ;bx points to our request header
  154.     mov al,byte ptr [bx + 2]    ;3rd byte of request header is command code
  155.     push ax                     ;to pass parameter(s) to a C function,
  156.     call driver_functions_      ;  push it(them) on stack and call function
  157.     pop ax                      ;caller must remove parameter(s) from stack
  158.  
  159.  
  160.             ;STEP 5
  161.             ; At this point we are done with the function our driver
  162.             ; was to perform.  Now we must copy our private request header
  163.             ; back into the original request header DOS gave us a pointer
  164.             ; to back in the strategy function.
  165.  
  166.     mov es,cs:req_hdr_seg        ;load address for orig RH into es:di
  167.     mov di,cs:req_hdr_off
  168.     mov si,offset driver_rh_     ;ds:si  our (updated) copy
  169.     cld                          ;set direction to increment
  170.     xor cx,cx                    ;clear out cx
  171.     mov cl,[si]                  ;length is at first byte 
  172.     rep movsb                    ; ... and copy it 
  173.  
  174.  
  175.             ;STEP 6
  176.             ; Restore machine state saved in STEP 0
  177.             ; and return to DOS
  178.  
  179.     cli                    ;machine state restore should not be interrupted
  180.     mov ax,cs:caller_ss    ;switch to caller's stack frame
  181.     mov ss,ax
  182.     mov ax,cs:caller_sp
  183.     mov sp,ax
  184.     popf                   ; ... pop all of it ...
  185.     pop bp
  186.     pop di
  187.     pop si
  188.     pop dx
  189.     pop cx
  190.     pop bx
  191.     pop ax
  192.     pop es
  193.     pop ds
  194.     sti                    ;enable interrrupts
  195.     ret                    ; ... back to dos and bye bye
  196.  
  197. prn_driver    endp         ;end of driver code
  198.  
  199.  
  200. codeseg    ends
  201.  
  202.     
  203.  
  204.     ;Data segment, contains our local stack space
  205.     ;  and C addressable copy of request header
  206.  
  207. dataseg  segment para public 'DATA'
  208.                                 
  209.     public c_stack_top
  210.  
  211.     db  PRIVATE_STACK_SIZ dup (0)
  212. c_stack_top  label  word
  213.  
  214.     public  driver_rh_
  215. driver_rh_  db  32 dup (0)   ;C addressable copy of request header
  216.  
  217. dataseg    ends
  218.  
  219.  
  220. END    
  221.  
  222.  
  223.  
  224. Listing Two
  225.  
  226. /**  rh.h
  227.     Device Driver Request Header structure definition
  228.     and status word #define's
  229. copyright (c) 1987 Andy Klein
  230. **/
  231.  
  232.  
  233. typedef struct
  234. {
  235.     unsigned char length,       /* length of header */
  236.                   unit,         /* unit code ... which unit to use */
  237.                   cmd;          /* command to execute */
  238.     unsigned int  status;       /* status of operation */
  239.     unsigned char reserved[8],
  240.                   media_type;   /* media descriptor byte, block dev only */
  241.     unsigned int  xfer_buf_offset,
  242.                   xfer_buf_segment,
  243.                   xfer_count;
  244.     char          dummy[32 - 20];
  245.                                 /* data for operation */
  246. } request_hdr;
  247.  
  248.  
  249. #define  ERROR_MASK         32768
  250. #define  BUSY_MASK          1024
  251. #define  DONE_MASK          512
  252.  
  253. #define  WRITE_PROTECTED    0x00
  254. #define  UNKNOWN_UNIT       0x01
  255. #define  DEV_NOT_READY      0x02
  256. #define  UNKNOWN_CMD        0x03
  257. #define  CRC_ERROR          0x04
  258. #define  BAD_DRIVE_REQ_LEN  0x05
  259. #define  SEEK_ERROR         0x06
  260. #define  UNKOWN_MEDIA       0x07
  261. #define  SECTOR_NOT_FOUND   0x08
  262. #define  PRN_NO_PAPER       0x09
  263. #define  WRITE_FAULT        0x0A
  264. #define  READ_FAULT         0x0B
  265. #define  GENERAL_FAILURE    0x0C
  266. #define  INVALID_DISK_CHG   0x0F
  267.  
  268.  
  269.  
  270.  
  271.  
  272. Listing Three
  273.  
  274. /**  drvfunc.c
  275.         Device Driver for DOS 2.x, 3.x
  276.         This is the function table that is called once
  277.         the interrupt function has established addressability
  278. copyright (c) 1987 Andy Klein
  279. **/
  280. #define LAST_FUNCTION 15
  281. #define Q_FUNCTIONS   LAST_FUNCTION + 1
  282.  
  283. extern void init(), output_status(), output(), output_flush(),    
  284.     output_verf(), bad_cmd();
  285.  
  286.     /**    
  287.         function_table is an array of pointers to functions
  288.         returning nothing (void).  It is analogous to a jump table
  289.         in assembler.
  290.     **/
  291. void (* function_table[Q_FUNCTIONS])() = {
  292.     /* 0 */        init,
  293.     /* 1  */    bad_cmd,            /* media check */
  294.     /* 2  */    bad_cmd,            /* build bpb */
  295.     /* 3  */    bad_cmd,            /* ioctl input */
  296.     /* 4  */    bad_cmd,            /* input */    
  297.     /* 5  */    bad_cmd,            /* input no wait */
  298.     /* 6  */    bad_cmd,            /* input status */
  299.     /* 7  */    bad_cmd,            /* input_flush */
  300.     /* 8  */    output,
  301.     /* 9  */    output_verf,
  302.     /* 10 */    output_status,
  303.     /* 11 */    output_flush,
  304.     /* 12 */    bad_cmd,            /* ioctl output */ 
  305.     /* 13 */    bad_cmd,            /* open device */
  306.     /* 14 */    bad_cmd,            /* close device */
  307.     /* 15 */    bad_cmd             /* removable_media */
  308. };
  309.  
  310.  
  311. void
  312. driver_functions(cmd)
  313. int cmd;
  314. {
  315.     if ( cmd > LAST_FUNCTION )
  316.         (void) bad_cmd();
  317.     else
  318.         (void) (* function_table[cmd])();
  319. }/* driver_functions() */
  320.  
  321.  
  322.  
  323.  
  324. Listing Four
  325.  
  326. /**  error.c
  327.      Error handler for printer driver
  328. copyright (c) 1987 Andy Klein
  329. **/
  330. #include "rh.h"
  331.  
  332. extern request_hdr driver_rh;
  333.  
  334. void
  335. bad_cmd()
  336. {
  337.     driver_rh.status = ERROR_MASK | UNKNOWN_CMD;
  338. }
  339.  
  340.  
  341. #define TIME_OUT  1
  342. #define IO_ERR    8
  343. #define NO_PAPER  32
  344. #define BUSY      128
  345.  
  346.  
  347. void
  348. driver_error(stat)
  349. int stat;
  350. {
  351.     int err_code;
  352.  
  353.     if ( stat & ERROR_MASK )
  354.         stat ^= ERROR_MASK;
  355.     switch ( stat )
  356.     {
  357.         case TIME_OUT:    err_code = DEV_NOT_READY;
  358.                           break;
  359.         case IO_ERR:      err_code = GENERAL_FAILURE;
  360.                           break;
  361.         case NO_PAPER:    err_code = PRN_NO_PAPER;
  362.                           break;
  363.         case BUSY:        err_code = DEV_NOT_READY;
  364.                           break;
  365.         default:          err_code = GENERAL_FAILURE;
  366.                           break;
  367.     }
  368.     driver_rh.status = ERROR_MASK | err_code;
  369. }/* driver_error() */
  370.  
  371.  
  372.  
  373.  
  374.  
  375. Listing Five
  376.  
  377. /**  init.c
  378.         Printer driver initialization 
  379. copyright (c) 1987 Andy Klein
  380. **/
  381. #include "rh.h" 
  382.  
  383. extern request_hdr driver_rh;
  384.  
  385. char *title = "\nPrinter Device Driver for Okidata 92";
  386. char *copyw  = "copyright 1987 (c) Andy Klein\n";
  387.  
  388.  
  389. void
  390. init()
  391. {
  392.     extern unsigned _Uend;    
  393.               /* _Uend is inserted by the Aztec linker */
  394.     unsigned show_cs();
  395.     void reset_printer(), initialize_oki92();
  396.  
  397.     puts(title);
  398.     puts(copyw);
  399.     (void) reset_printer();
  400.     (void) initialize_oki92();
  401.          /* set ending address of driver, set status word */
  402.     driver_rh.xfer_buf_segment = show_cs();
  403.     driver_rh.xfer_buf_offset = (unsigned int)&_Uend;
  404.     driver_rh.status = DONE_MASK;
  405. } /* init() */
  406.  
  407.  
  408. #define ELITE_FONT  28
  409.  
  410. void
  411. initialize_oki92()
  412. {
  413.     char_2_prn(ELITE_FONT);
  414. }/* initialize_oki92() */
  415.  
  416.  
  417.  
  418.  
  419.  
  420. Listing Six
  421.  
  422. ;  show_cs.asm
  423. ;    c call is (unsigned) show_cs();
  424. ;    Returns contents of cs register
  425. ;copyright (c) 1987 Andy Klein
  426.  
  427. include lmacros.h
  428.  
  429. procdef        show_cs
  430.     mov ax, cs
  431.     pret
  432.     pend show_cs
  433.  
  434. finish
  435.  
  436.  
  437.  
  438.  
  439. Listing Seven
  440.  
  441. /**  output.c
  442.         Printer driver output functions
  443. copyright (c) 1987 Andy Klein
  444. **/
  445. #include "rh.h"
  446.  
  447. extern request_hdr driver_rh;
  448.         
  449. void
  450. output()
  451. {
  452.     int stat;
  453.     unsigned  xfer_off, bytes_xferd;
  454.     register char outch;
  455.     char fetch_char();
  456.  
  457.     xfer_off = driver_rh.xfer_buf_offset;
  458.     for ( bytes_xferd = 0; bytes_xferd < driver_rh.xfer_count;
  459.             ++bytes_xferd, ++xfer_off ) 
  460.     {
  461.         outch = fetch_char(driver_rh.xfer_buf_segment, xfer_off); 
  462.         if ( (stat = char_2_prn(outch)) )
  463.         {
  464.             (void) driver_error(stat);
  465.             break;
  466.         }
  467.     }
  468.  
  469.     driver_rh.xfer_count = bytes_xferd;
  470.     if ( ! stat )
  471.         driver_rh.status = DONE_MASK;
  472.     else
  473.         driver_rh.status = stat;
  474. }/* output() */
  475.  
  476.  
  477. void
  478. output_verf()
  479. {
  480.     (void) output();
  481. }/* out_verf() */
  482.  
  483.  
  484.  
  485. void
  486. output_status()
  487. {
  488.     /**
  489.         if device is currently doing an operation,
  490.         driver_rh.status = BUSY_MASK & DONE_MASK;
  491.         else if a write can begin immediately,
  492.         driver_rh.status = 0 & DONE_MASK;
  493.     **/
  494.     if ( printer_busy() )
  495.         driver_rh.status = BUSY_MASK & DONE_MASK;
  496.     else
  497.         driver_rh.status = DONE_MASK;
  498. }/* output_status() */
  499.  
  500.  
  501.  
  502. void
  503. output_flush()
  504. {
  505.     /** 
  506.         terminate all pending requests, 
  507.         meaningless for this device
  508.     **/
  509.     driver_rh.status = DONE_MASK;
  510. }/* output_flush() */
  511.  
  512.  
  513.  
  514.  
  515.  
  516. Listing Eight
  517.  
  518. ;  prlport.asm
  519. ;    low level parallel port output functions
  520. ;copyright (c) Andy Klein 1987
  521.  
  522.  
  523. include lmacros.h       ;Aztec C macros for assembly language functions
  524.                         ; for other environments replace with calling 
  525.                         ; conventions for your complier
  526.  
  527.  
  528. ERROR_MASK   equ    32768
  529. PRINTER_INT  equ    017H
  530. PRINTER_ID   equ    0            ;lpt1 = 0, lpt2 = 1, lpt3 = 2
  531.  
  532.     ;printer commands, put into ah
  533. PRINT_CHAR   equ    0
  534. INIT_PRN     equ    1
  535. READ_STAT    equ    2
  536.  
  537.     ;printer status byte error codes, returned in ah
  538. TIME_OUT    equ    1
  539. IO_ERR      equ    8
  540. NO_PAPER    equ    32
  541. BUSY        equ    128
  542.  
  543. PRINTER_FAILURE   equ   TIME_OUT+IO_ERR+NO_PAPER
  544.  
  545.  
  546.     ;C call is (void) reset_printer();
  547.     ;no value returned
  548. procdef reset_printer
  549.         mov ah,INIT_PRN
  550.         mov dx,PRINTER_ID
  551.         sti
  552.         int PRINTER_INT
  553.         xor ax,ax
  554.         pret
  555. pend reset_printer
  556.  
  557.  
  558.     ;C call is printer_busy();
  559.     ;returns 0 (FALSE) if not busy, nonzero (TRUE) if busy
  560. procdef printer_busy
  561.         mov ah,READ_STAT
  562.         mov dx,PRINTER_ID
  563.         sti
  564.         int PRINTER_INT
  565.         and ah,BUSY
  566.         jz  printer_is_busy
  567.         xor ax,ax
  568.         pret
  569.     printer_is_busy:
  570.         mov ax,1
  571.         pret
  572. pend printer_busy
  573.  
  574.  
  575.  
  576.     ;  C call is   (char) fetch_char(segm, offs);
  577.     ;    gets the character at segm:offs and
  578.     ;    returns it
  579.  
  580. procdef fetch_char,<<segm,word>,<offs,word>>
  581.         push ds
  582.         mov bx,offs
  583.         mov ds,segm
  584.         mov al,byte ptr ds:[bx]
  585.         and ax,0ffH        
  586.         pop ds
  587.         pret
  588. pend fetch_char
  589.  
  590.  
  591.     ;C call is char_2_prn(outch);
  592.     ;    prints outch on PRINTER_ID
  593.     ; returns 0 if ok, error code 
  594.  
  595. procdef char_2_prn,<<outch,byte>>
  596.         mov al,outch
  597.         mov ah,PRINT_CHAR
  598.         mov dx,PRINTER_ID
  599.         sti
  600.         int PRINTER_INT
  601.         test ah,PRINTER_FAILURE
  602.         jnz printer_has_failed
  603.         xor ax,ax
  604.         pret
  605.     printer_has_failed:
  606.         mov al,ah                ;result code in ah, mov it to al
  607.         and ax,PRINTER_FAILURE  
  608.         pret
  609. pend char_2_prn
  610.  
  611.  
  612. finish
  613.  
  614.  
  615.  
  616.  
  617.  
  618.